﻿using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Globalization;

namespace Nature.Numerics
{
    [DebuggerDisplay("Vector[{Length}]")]
    public struct Vector : IVector, IFormattable, IEquatable<Vector>
    {
        #region Static Methods

        public static void Assign<TVector>(TVector lhs, double[] rhs)
            where TVector : IVector
        {
            Debug.Assert(lhs.Length == rhs.Length);
            for (int i = 0; i < lhs.Length; ++i)
            {
                lhs[i] = rhs[i];
            }
        }

        public static void Assign<TVector1, TVector2>(TVector1 lhs, TVector2 rhs)
            where TVector1 : IVector
            where TVector2 : IVector
        {
            Debug.Assert(lhs.Length == rhs.Length);
            for (int i = 0; i < lhs.Length; ++i)
            {
                lhs[i] = rhs[i];
            }
        }

        public static Vector Product<TMatrix, TVector>(TMatrix m, TVector v)
            where TMatrix : INxN
            where TVector : IVector
        {
            Vector result = new Vector(v.Length);
            for (int i = 0; i < result.Length; ++i)
            {
                double sum = 0.0;
                result[i] = 0.0;
                for (int j = 0; j < result.Length; ++j)
                {
                    sum += m[i, j] * v[j];
                }
                result[i] = sum;
            }
            return result;
        }

        public static Vector Product<TMatrix>(TMatrix m, string v)
            where TMatrix : INxN
        {
            Vector vector = v;
            return Vector.Product(m, vector);
        }

        #endregion

        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
        double[] m_array;

        public int Length { get { return m_array.Length; } }



        public Vector(int nva, Func<int, double> func)
            : this(nva)
        {
            for (int i = 0; i < nva; ++i)
            {
                m_array[i] = func(i);
            }
        }

        public Vector(string text)
            : this()
        {
            string pattern =
                @"(?xi) 
                    [+-]? \s*
                    (?:                    
                        (?: 
                            (?:\d+\.?\d*) | (?:\.\d+) 
                        )                            
                        (?:[edf][+-]?\d{1,3})?               
                    )                    
                ";
            m_array = Regex.Matches(text, pattern)
                .Cast<Match>()
                .Select(m => double.Parse(m.Value))
                .ToArray(); ;
        }

        public Vector(double[] array)
            : this()
        {
            m_array = array;
        }

        public Vector(double[] array, bool clone)
            : this(array)
        {
            if (true == clone)
            {
                m_array = new double[array.Length];
                array.CopyTo(m_array, 0);
            }

        }

        public static implicit operator Vector(string vector)
        {
            return new Vector(vector);
        }


        public Vector(IVector array)
            : this()
        {

        }

        public Vector(int length)
            : this(new double[length])
        {

        }

        public Vector(int length, double value)
            : this(length)
        {
            for (int i = 0; i < length; ++i)
            {
                m_array[i] = value;
            }
        }

        public static implicit operator Vector(double[] array)
        {
            return new Vector(array);
        }

        public static implicit operator double[](Vector vector)
        {
            return vector.m_array;
        }

        public bool IsNull
        {
            get { return (m_array == null); }
        }

        #region IVector Members

        public double this[int i]
        {
            get { return m_array[i]; }
            set { m_array[i] = value; }
        }

        #endregion

        #region IEnumerable<double> Members

        public IEnumerator<double> GetEnumerator()
        {
            IEnumerable<double> enumerable = m_array;
            return enumerable.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return m_array.GetEnumerator();
        }

        #endregion

        #region IFormattable Members

        public string ToString(string format)
        {
            return ToString(format, CultureInfo.CurrentCulture);
        }

        public string ToString(string format, IFormatProvider formatProvider)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var value in m_array)
            {
                sb.AppendFormat(format, value);
            }
            return sb.ToString();
        }

        #endregion

        #region IEquatable<Vector> Members

        public bool Equals(Vector other)
        {
            if (m_array == other.m_array) { return true; }
            if (Length != other.Length) { return false; }
            for (int iva = 0; iva < Length; ++iva)
            {
                if (this[iva] != other[iva])
                {
                    return false;
                }
            }
            return true;
        }

        #endregion
    }
}
